1   /*
2    * Copyright (C) 2011 The Guava Authors
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5    * use this file except in compliance with the License. You may obtain a copy of
6    * the License at
7    *
8    * http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13   * License for the specific language governing permissions and limitations under
14   * the License.
15   */
16  
17  package com.google.common.collect;
18  
19  import static com.google.common.collect.BoundType.CLOSED;
20  import static com.google.common.collect.BoundType.OPEN;
21  
22  import com.google.common.annotations.GwtCompatible;
23  import com.google.common.annotations.GwtIncompatible;
24  import com.google.common.collect.Multiset.Entry;
25  
26  import java.util.Comparator;
27  import java.util.Iterator;
28  import java.util.NavigableSet;
29  import java.util.NoSuchElementException;
30  import java.util.SortedSet;
31  
32  import javax.annotation.Nullable;
33  
34  /**
35   * Provides static utility methods for creating and working with
36   * {@link SortedMultiset} instances.
37   *
38   * @author Louis Wasserman
39   */
40  @GwtCompatible(emulated = true)
41  final class SortedMultisets {
42    private SortedMultisets() {
43    }
44  
45    /**
46     * A skeleton implementation for {@link SortedMultiset#elementSet}.
47     */
48    static class ElementSet<E> extends Multisets.ElementSet<E> implements
49        SortedSet<E> {
50      private final SortedMultiset<E> multiset;
51  
52      ElementSet(SortedMultiset<E> multiset) {
53        this.multiset = multiset;
54      }
55  
56      @Override final SortedMultiset<E> multiset() {
57        return multiset;
58      }
59  
60      @Override public Comparator<? super E> comparator() {
61        return multiset().comparator();
62      }
63  
64      @Override public SortedSet<E> subSet(E fromElement, E toElement) {
65        return multiset().subMultiset(fromElement, CLOSED, toElement, OPEN).elementSet();
66      }
67  
68      @Override public SortedSet<E> headSet(E toElement) {
69        return multiset().headMultiset(toElement, OPEN).elementSet();
70      }
71  
72      @Override public SortedSet<E> tailSet(E fromElement) {
73        return multiset().tailMultiset(fromElement, CLOSED).elementSet();
74      }
75  
76      @Override public E first() {
77        return getElementOrThrow(multiset().firstEntry());
78      }
79  
80      @Override public E last() {
81        return getElementOrThrow(multiset().lastEntry());
82      }
83    }
84  
85    /**
86     * A skeleton navigable implementation for {@link SortedMultiset#elementSet}.
87     */
88    @GwtIncompatible("Navigable")
89    static class NavigableElementSet<E> extends ElementSet<E> implements NavigableSet<E> {
90      NavigableElementSet(SortedMultiset<E> multiset) {
91        super(multiset);
92      }
93  
94      @Override
95      public E lower(E e) {
96        return getElementOrNull(multiset().headMultiset(e, OPEN).lastEntry());
97      }
98  
99      @Override
100     public E floor(E e) {
101       return getElementOrNull(multiset().headMultiset(e, CLOSED).lastEntry());
102     }
103 
104     @Override
105     public E ceiling(E e) {
106       return getElementOrNull(multiset().tailMultiset(e, CLOSED).firstEntry());
107     }
108 
109     @Override
110     public E higher(E e) {
111       return getElementOrNull(multiset().tailMultiset(e, OPEN).firstEntry());
112     }
113 
114     @Override
115     public NavigableSet<E> descendingSet() {
116       return new NavigableElementSet<E>(multiset().descendingMultiset());
117     }
118 
119     @Override
120     public Iterator<E> descendingIterator() {
121       return descendingSet().iterator();
122     }
123 
124     @Override
125     public E pollFirst() {
126       return getElementOrNull(multiset().pollFirstEntry());
127     }
128 
129     @Override
130     public E pollLast() {
131       return getElementOrNull(multiset().pollLastEntry());
132     }
133 
134     @Override
135     public NavigableSet<E> subSet(
136         E fromElement, boolean fromInclusive, E toElement, boolean toInclusive) {
137       return new NavigableElementSet<E>(multiset().subMultiset(
138           fromElement, BoundType.forBoolean(fromInclusive),
139           toElement, BoundType.forBoolean(toInclusive)));
140     }
141 
142     @Override
143     public NavigableSet<E> headSet(E toElement, boolean inclusive) {
144       return new NavigableElementSet<E>(
145           multiset().headMultiset(toElement, BoundType.forBoolean(inclusive)));
146     }
147 
148     @Override
149     public NavigableSet<E> tailSet(E fromElement, boolean inclusive) {
150       return new NavigableElementSet<E>(
151           multiset().tailMultiset(fromElement, BoundType.forBoolean(inclusive)));
152     }
153   }
154 
155   private static <E> E getElementOrThrow(Entry<E> entry) {
156     if (entry == null) {
157       throw new NoSuchElementException();
158     }
159     return entry.getElement();
160   }
161 
162   private static <E> E getElementOrNull(@Nullable Entry<E> entry) {
163     return (entry == null) ? null : entry.getElement();
164   }
165 }